package wang.hex;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author fox
 * @Class TracerInterceptor
 * @Description
 * @Date 2020/12/24 11:41
 */
public class TracerInterceptor implements MethodInterceptor {
    private Object realObject;

    TracerInterceptor(Object realObject) {
        this.realObject = realObject;
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object object = null;
        List<TracerMethodVisitor> list = new LinkedList<TracerMethodVisitor>();
        //执行before
        for (TracerMethodVisitor visitor : TracerFactory.visitors) {
            try {
                //判断能不能执行
                if (visitor.accept(o.getClass().getName(), method.getName())) {
                    visitor.before(realObject, method, objects);
                    list.add(visitor);
                }
            } catch (Exception e) {
                visitor.exception(e);
            }
        }
        try {
            object = method.invoke(this.realObject, objects);
        } catch (Exception e) {
            //执行exception
            for (TracerMethodVisitor tracerMethodVisitor : list) {
                try {
                    tracerMethodVisitor.exception(e);
                } catch (Exception e1) {
                    tracerMethodVisitor.exception(e1);
                }
            }

            throw e;
        } finally {
            //执行end方法
            for (TracerMethodVisitor tracerMethodVisitor : list) {
                try {
                    tracerMethodVisitor.end(object);
                } catch (Exception e1) {
                    tracerMethodVisitor.exception(e1);
                }
            }
        }
        //很关键 把我们的返回值也变成代理
        //这样返回的object执行的方法也被监控了
        //只要有个入口类 它下面的所有方法全能被监控  final的会跳过
        Object tracerFromObject = TracerFactory.getTracerFromObject(object);
        for (TracerMethodVisitor tracerMethodVisitor : list) {
            try {
                tracerMethodVisitor.retProxy(object);
            } catch (Exception e1) {
                tracerMethodVisitor.exception(e1);
            }
        }

        return tracerFromObject;
    }
}
